package middleware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"haodayizhi/global"
	"haodayizhi/model"
	mtype "haodayizhi/types"
	util "haodayizhi/utils"
	"io"
	"net/http"
	"runtime"
	"runtime/debug"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

var (
	ipBlacklist       = make(map[string]time.Time)
	mu                sync.Mutex
	requestTimestamps = make(map[string][]time.Time)
	windowDuration    = 10 * time.Second // 时间窗口
)

const (
	TOKEN_NAME           = "Authorization"
	TOKEN_PREFIX         = "Bearer: "
	API_KEY              = "X-API-Key"
	RENEW_TOKEN_DURATION = 10 * 60 * time.Second
)

// API密钥中间件
func ApiKeyMiddleware(c *gin.Context) {
	response := mtype.ResponseType{
		Code:    http.StatusUnauthorized,
		Message: "Forbidden",
		Result:  nil,
	}
	apiKey := c.GetHeader(API_KEY)
	if apiKey == "" || apiKey != global.Config.Security.APIKey {
		util.LogMessage("error", fmt.Sprintf(c.FullPath()+" ===> "+"Unauthorized access attempt from IP: %s", c.ClientIP()))
		response.Code = http.StatusForbidden
		response.Message = "Forbidden"
		c.JSON(http.StatusForbidden, response)
		c.Abort()
		return
	}
	c.Next()
}
func AuthMiddleware() gin.HandlerFunc {
	response := mtype.ResponseType{
		Code:    http.StatusUnauthorized,
		Message: "Unauthorized",
		Result:  nil,
	}
	return func(c *gin.Context) {
		tokenString := c.GetHeader(TOKEN_NAME)
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, response)
			c.Abort()
			return
		}

		tokenString = tokenString[len(TOKEN_PREFIX):]
		tokenString = strings.TrimSpace(tokenString)

		claims, err := util.ParseJWT(tokenString)

		if claims.UserID <= 0 || err != nil {
			c.JSON(http.StatusUnauthorized, response)
			c.Abort()
			return
		}
		redisToken, err := util.GetToken(claims.Email)

		if err != nil || redisToken != tokenString {
			c.JSON(http.StatusUnauthorized, response)
			c.Abort()
			return
		}
		// token 过期 直接返回

		TokenExpire, err := util.GetTokenExpiration(claims.Email)

		// 过期时间对比
		if err != nil || TokenExpire <= 0 {
			c.JSON(http.StatusUnauthorized, response)
			c.Abort()
			return
		}
		// 如果小于十分钟
		if TokenExpire <= RENEW_TOKEN_DURATION.Seconds() {
			// 重新生成token
			newToken, err := util.GenerateJWT(claims.UserID, claims.Email)
			if err != nil {
				c.JSON(http.StatusUnauthorized, response)
				c.Abort()
				return
			}
			// 更新redis
			err = util.SetTokenToRedis(claims.Email, newToken)
			if err != nil {
				c.JSON(http.StatusUnauthorized, response)
				c.Abort()
				return
			}
			c.Header("Authorization", TOKEN_PREFIX+newToken)
		}

		user := model.User{}
		// 看查询到用户不
		userInfo, err := user.GetUserByID(claims.UserID)

		if err != nil || userInfo.ID != claims.UserID {
			c.JSON(http.StatusUnauthorized, response)
			c.Abort()
			return
		}
		// 将解析的用户信息添加到上下文
		c.Set(global.LOG_USER, mtype.TokenConfig{
			UserID: userInfo.ID,
			Email:  userInfo.Email,
		})
		c.Next()
	}
}

// 通过uuid查看到用户是都登录，以及登录对比
func AuthUuidMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		uuidString, err := c.Cookie(global.UUID)
		if uuidString == "" || err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"message": "Missing token"})
			c.Abort()
			return
		}
		cookieString, err := c.Cookie(global.Cookie)
		if err != nil || cookieString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"message": "Missing token"})
			c.Abort()
			return
		}
		uuidString = strings.TrimSpace(uuidString)
		cookie, err := util.GetUuidValue(uuidString)

		if cookie == "" || err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"message": "Invalid token"})
			c.Abort()
			return
		}
		if cookie != cookieString {
			c.JSON(http.StatusUnauthorized, gin.H{"message": "Invalid token"})
			c.Abort()
			return
		}
		c.Next()
	}
}

// 跨域资源共享控制中间件
func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, X-API-Key")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}
		c.Next()
	}
}

// 请求速率限制中间件
func RateLimiter() gin.HandlerFunc {
	return func(c *gin.Context) {
		clientIP := c.ClientIP()
		mu.Lock()
		defer mu.Unlock()
		// 当前时间
		now := time.Now()

		// 清理超出时间窗口的请求时间
		timestamps := requestTimestamps[clientIP]
		var validTimestamps []time.Time
		for _, ts := range timestamps {
			if now.Sub(ts) <= windowDuration {
				validTimestamps = append(validTimestamps, ts)
			}
		}
		requestTimestamps[clientIP] = validTimestamps

		// 检查是否黑名单
		if bannedUntil, blacklisted := ipBlacklist[clientIP]; blacklisted {
			if now.Before(bannedUntil) {
				c.JSON(http.StatusForbidden, gin.H{"message": "IP Blacklisted"})
				c.Abort()
				return
			} else {
				// 黑名单超时，解除封禁
				delete(ipBlacklist, clientIP)
				util.LogMessage("info", fmt.Sprintf("IP %s removed from blacklist", clientIP))
			}
		}

		// 检查速率限制
		if len(requestTimestamps[clientIP]) >= global.Config.Security.RateLimit {
			ipBlacklist[clientIP] = now.Add(time.Duration(global.Config.Security.BanTime) * time.Second)
			util.LogMessage("error", fmt.Sprintf("IP %s blacklisted for exceeding rate limit", clientIP))
			c.JSON(http.StatusForbidden, gin.H{"message": "Too many requests"})
			c.Abort()
			return
		}

		// 记录当前请求时间
		requestTimestamps[clientIP] = append(requestTimestamps[clientIP], now)

		c.Next()
	}
}

// 访问日志中间件
func AccessLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Next()
		util.LogMessage("info", fmt.Sprintf("Ip:%s,  Access: Path: %s, Method: %s, Status: %d", c.ClientIP(), c.Request.URL.Path, c.Request.Method, c.Writer.Status()))
	}
}

// 错误处理中间件
func ErrHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// 获取堆栈信息
				stackTrace := string(debug.Stack())
				// 获取调用者的文件和行号
				_, file, line, _ := runtime.Caller(4)
				errorMsg := fmt.Sprintf("Recovered error in file %s at line %d: %v\nStack trace:\n%s", file, line, err, stackTrace)
				util.LogMessage("error", errorMsg)
				c.JSON(http.StatusInternalServerError, gin.H{"message": "Internal Server Error"})
			}
		}()
		c.Next()
	}
}

// 时间统一转化中间件

// TimeMiddleware 处理请求体中的时间字段
func TimeMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 如果是 GET 请求，直接进入下一个中间件或处理器
		if c.Request.Method == "GET" {
			c.Next()
			return
		}

		// 处理 /user/upload 接口
		if strings.HasPrefix(c.Request.URL.Path, "/user/upload") {
			c.Next()
			return
		}

		// 读取请求体
		body, err := io.ReadAll(c.Request.Body)
		if err != nil {
			c.JSON(400, gin.H{"error": "Failed to read request body"})
			c.Abort()
			return
		}

		// 如果请求体为空，直接进入下一个中间件或处理器
		if len(body) == 0 {
			c.Next()
			return
		}

		// 解析 JSON
		var reqBody map[string]interface{}
		if err := json.Unmarshal(body, &reqBody); err != nil {
			c.JSON(400, gin.H{"error": "Invalid JSON format"})
			c.Abort()
			return
		}

		// 处理时间字段
		timeFields := map[string]string{
			"birth":     "2006-01-02",
			"createAt":  "2006-01-02 15:04:05",
			"updateAt":  "2006-01-02 15:04:05",
			"deletedAt": "2006-01-02 15:04:05",
		}

		for field, layout := range timeFields {
			if timeStr, ok := reqBody[field].(string); ok {
				parsedTime, err := time.Parse(layout, timeStr)
				if err != nil {
					c.JSON(400, gin.H{"error": fmt.Sprintf("Invalid time format for %s", field)})
					c.Abort()
					return
				}
				reqBody[field] = parsedTime
			}
		}

		// Re-encode modified body
		modifiedBody, err := json.Marshal(reqBody)
		if err != nil {
			c.JSON(500, gin.H{"error": "Failed to marshal updated request body"})
			c.Abort()
			return
		}

		// Create a new reader for the modified body and reset Content-Length
		c.Request.Body = io.NopCloser(bytes.NewBuffer(modifiedBody))
		c.Request.ContentLength = int64(len(modifiedBody))

		// Continue to the next middleware/handler
		c.Next()
	}
}
